#! /usr/bin/env python
# -*- coding:utf-8 -*-
# vim:fileencoding=utf-8

from pyscript.core import singleton
import sys, time
import mysql.connector
from mysql.connector import errorcode


@singleton
class Database(object):

    def __init__(self, **kargs):
        default_db_config = dict(host = 'localhost',
                                 port = 3306,
                                 user = 'root',
                                 password = '',
                                 charset = 'utf8')
        db_config = kargs.get('db', default_db_config) if kargs.get('db', default_db_config) else default_db_config
        self._rdb_config = kargs.get('rdb', db_config) if kargs.get('rdb', db_config) else db_config
        self._wdb_config = kargs.get('wdb', db_config) if kargs.get('wdb', db_config) else db_config


    def _intenal_rdb(self):
        self.rdb = self.rdb if hasattr(self, '_rdb') else self._connect('rdb')


    def _intenal_wdb(self):
        self.wdb = self.wdb if hasattr(self, '_wdb') else self._connect('wdb')


    def _connect(self, db):
        config = getattr(self, """_%s_config""" % db)

        try:
            cnx = mysql.connector.connect(**config)
        except mysql.connector.Error as err:
            if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
                print("Something is wrong with your user name or password")
            elif err.errno == errorcode.ER_BAD_DB_ERROR:
                print("Database does not exists")
            else:
                print(err)

            print "system exit, exit 2"
            sys.exit(2)
        except Exception as e:
            print "Exception can't handle, exit 2"
            sys.exit(2)
        else:
            return cnx


    @property
    def rdb(self):
        self._ping('rdb')
        return self._rdb


    @rdb.setter
    def rdb(self, value):
        self._rdb = value


    @rdb.deleter
    def rdb(self):
        self._close('rdb')


    @property
    def wdb(self):
        self._ping('wdb')
        return self._wdb


    @wdb.setter
    def wdb(self, wdb):
        self._wdb = wdb


    @wdb.deleter
    def wdb(self):
        self._close('wdb')


    def _ping(self, db='rdb'):
        attr = self._intenal_attr(db)

        if not attr.is_connected():
            self._reconnect(db)


    def _reconnect(self, db='rdb', timeout = 30, times = 3):
        attr = self._intenal_attr(db)

        for i in range(times):
            try:
                print """Reconnect to %s %d times""" % (db[1:], i+1)
                if 0 == i:
                    attr.reconnect()
                else:
                    attr = self._connect(db)

                print "Reconnect Success"
                break
            except Exception as e:
                if i < (times - 1):
                    print """Reconnect Exception, sleep %2d seconds, message: %s""" % (timeout, str(e))
                    time.sleep(timeout)
                else:
                    print """Can not connect to server, exit 1"""
                    sys.exit(1)


    def _intenal_attr(self, db):
        attr_name = """_%s""" % db

        if not hasattr(self, attr_name):
            self._intenal_connect(db)

        return getattr(self, attr_name)


    def _intenal_del_attr(self, db):
        attr_name = """_%s""" % db

        if hasattr(self, attr_name):
            delattr(self, attr_name)


    def _intenal_connect(self, db):
        getattr(self, """_intenal_%s""" % db)()


    def _rclose(self):
        self._close('rdb')


    def _wclose(self):
        self._close('wdb')


    def _close(self, db='wdb'):
        self._intenal_attr(db).close()
        self._intenal_del_attr(db)

